﻿using System;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;

namespace Kaleida.ServiceMonitor.Framework
{
    public class Percentage
    {
        private readonly decimal percentValue; // e.g. 50 = 50%

        public static bool TryParse(string text, out Percentage percent)
        {
            return TryParse(text, CultureInfo.CurrentCulture, out percent);
        }

        public static bool TryParse(string text, CultureInfo culture, out Percentage percent)
        {
            var percentMatch = Regex.Match(text, @"^\s*(-?[0-9.,]+)\s*%$");
            if (percentMatch.Success && percentMatch.Groups.Count == 2)
            {
                decimal decimalValue;
                if (decimal.TryParse(percentMatch.Groups[1].Value, NumberStyles.Number, culture, out decimalValue))
                {
                    percent = new Percentage(decimalValue);
                    return true;
                }
            }

            percent = null;
            return false;
        }

        public static Percentage FromPercentage(decimal percentValue)
        {
            return new Percentage(percentValue);
        }

        public static Percentage FromDecimal(decimal value)
        {
            return new Percentage(value * 100);
        }

        private Percentage(decimal percentValue)
        {
            this.percentValue = Math.Round(percentValue, 4);
        }

        public decimal PercentValue
        {
            get { return percentValue; }
        }

        public decimal Value
        {
            get { return percentValue / 100m; }
        }

        public override string ToString()
        {
            return ToString(CultureInfo.CurrentCulture);
        }

        public string ToString(CultureInfo culture)
        {
            string numberFormat = "N" + SignificantDecimalsCount();
            return percentValue.ToString(numberFormat, culture) + "%";
        }

        private int SignificantDecimalsCount()
        {
            string fullPrecision = percentValue.ToString("0.0000", CultureInfo.InvariantCulture);

            if (fullPrecision.Contains("."))
            {
                var trailingZeroCount = fullPrecision.Reverse().TakeWhile(i => i == '0').Count();
                var decimalPlaceCount = fullPrecision.Length - fullPrecision.IndexOf('.') - 1;
                return decimalPlaceCount - trailingZeroCount;
            }

            return 0;
        }


        public bool Equals(Percentage other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return other.percentValue == percentValue;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof(Percentage)) return false;
            return Equals((Percentage)obj);
        }

        public override int GetHashCode()
        {
            return percentValue.GetHashCode();
        }

        public static bool operator ==(Percentage left, Percentage right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(Percentage left, Percentage right)
        {
            return !Equals(left, right);
        }
    }
}
